

package {
	import Box2D.Collision.b2Bound;
	import Box2D.Collision.Shapes.b2CircleShape;
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2FixtureDef;
	import Box2D.Dynamics.b2World;
	import Box2D.Dynamics.Joints.b2RevoluteJointDef;
	import com.ecity.cn.Door;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.geom.Point;
	import flash.ui.Keyboard;

	public class MainView extends Sprite {
		private const PIXELS_TO_METRE:int = 30;
		private var _world:b2World;
		private static const BRES:Number = 1;
		private static const THICHNESS:Number = 30;
		private static const W:Number = 1024;
		private static const H:Number = 768;
		private static const CL:Number = 100;//corner's length
		
		private static const ST:Number = 100;//short border's thickniess
		private static const LT:Number = 200;//longer border's thickniess
		
		private static const TW:Number=720;
		private static const TH:Number = 520;
		
		private static const GW:Number=200;
		private static const GH:Number = 20;
		private var _door:Door;
		private var _gates:Array = new Array();
		private var forceD:Array = [1, -1, -1, 1, 1, -1, -1, 1];


		public function MainView(){
			this.createWorld();
			_door = new Door(_world);
			initWalls();
			addGateSystem();
			addBall(new Point(420, 330), 30, true,6, 0, 1);
			addBall(new Point(360, 130), 15, true,6, 0, 1);
			stage.addEventListener(Event.ENTER_FRAME, worldUpdate);
			stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyboardEvent);
		}
		private function createWorld():void {
			this._world = new b2World(new b2Vec2(0, 0), true);
			stage.addChild(this.debugDraw());
		}
		
		private function initWalls():void {
			addBox(new Point(W-CL- LT/2, H-THICHNESS/2), LT/2, THICHNESS/2, false, 1,0.3,1);
			addBox(new Point(CL+ LT/2, H-THICHNESS/2), LT/2, THICHNESS/2, false, 1, 0.3,BRES);
			addBox(new Point(W-CL- LT/2, THICHNESS/2), LT/2, THICHNESS/2, false, 1, 0.3,BRES);
			addBox(new Point(CL+ LT/2, THICHNESS/2), LT/2, THICHNESS/2, false, 1, 0.3,BRES);
			addBox(new Point(THICHNESS/2, CL+ST/2), THICHNESS/2, ST/2, false, 1, 0.3,BRES);
			addBox(new Point(THICHNESS/2, H-CL-ST/2), THICHNESS/2, ST/2, false, 1, 0.3,BRES);
			addBox(new Point(W-THICHNESS/2, CL+ST/2), THICHNESS/2, ST/2, false, 1, 0.3,BRES);
			addBox(new Point(W - THICHNESS / 2,H-CL-ST/2), THICHNESS / 2, ST / 2, false, 1, 0.3,BRES);
			for (var i:int = 0; i < 4; i++) {
				addCorners(i, 1, 0.3, 1);
			}
		}
		
		private function addBox(position:Point, halfWidth:Number, halfHeight:Number, isDynamic:Boolean, density:Number = 0, friction:Number = 0, restitution:Number = 0):b2Body {
			var bodyDef:b2BodyDef = new b2BodyDef();
			if (isDynamic) {
				bodyDef.type = b2Body.b2_dynamicBody;
			} else {
				bodyDef.type = b2Body.b2_staticBody;
			}
			bodyDef.position.Set(p2m(position.x), p2m(position.y));
			var body:b2Body = this._world.CreateBody(bodyDef);
			var boxShape:b2PolygonShape = new b2PolygonShape();
			//boxShape.GetVertexCount = 5;
			boxShape.SetAsBox(p2m(halfWidth),p2m(halfHeight));
			var boxFixtureDef:b2FixtureDef = _door.addFixtureDef(boxShape, density, friction, restitution);
			body.CreateFixture(boxFixtureDef);
			return body;
		}
		
		private function addGateSystem():void {
			var pAs:Array = [[300, 520], [500, 520], [300, 80], [500, 80], [80, 200], [80, 400], [720, 200], [720, 400]];
			var pOs:Array = [[300, 570],[500, 570],[300, 30],[500, 30],[30, 200], [30, 400],[770, 200], [770, 400]];
			var pDs:Array = [[340, 520], [460, 520], [340, 80], [460, 80], [80, 240], [80, 360], [720, 240], [720, 360]];
			var w:Number = 40;
			var h:Number = 3;
			for (var i:int = 0; i < pAs.length;i++) {
				var gate:b2Body;
				var gateBack:b2Body;
				if (i <4) {
					gate = addBox(new Point(pDs[i][0], pDs[i][1]), w, h, true, 30, 1, 0.5);
					if (i < 2) {
						gateBack = addBox(new Point(pDs[i][0], pDs[i][1]+6), 12, 1, true, 10, 1, 0);
					}else {
						gateBack = addBox(new Point(pDs[i][0], pDs[i][1]-6), 12, 1, true, 10, 1, 0);
					}
				}else {
					gate = addBox(new Point(pDs[i][0], pDs[i][1]), h, w, true, 30, 1, 0.5);
					if (i < 6) {
						gateBack = addBox(new Point(pDs[i][0]-6, pDs[i][1]), 1, 12, true, 10, 1, 0);
					}else {
						gateBack = addBox(new Point(pDs[i][0]+6, pDs[i][1]), 1, 12, true, 10, 1, 0);
					}
				}
				_gates[i] = gate;
				var anchor:b2Body = addBall(new Point(pAs[i][0], pAs[i][1]),5, false, 3, 0, 0);
				var sssss:b2Body = addBall(new Point(pOs[i][0], pOs[i][1]), 15, false,0, 0, 0);
				_door.addJoint(anchor, gate);
				_door.addWeldJoint(gate, gateBack);
			}
			
		}
		
		private function addBall(position:Point, radius:Number, isDynamic:Boolean, density:Number = 0, friction:Number = 0, restitution:Number = 0):b2Body {
			var bodyDef:b2BodyDef = new b2BodyDef();
			if (isDynamic) {
				bodyDef.type = b2Body.b2_dynamicBody;
			} else {
				bodyDef.type = b2Body.b2_staticBody;
			}
			bodyDef.position.Set(p2m(position.x),p2m(position.y));
			var body:b2Body = this._world.CreateBody(bodyDef);
			var ball:b2CircleShape = new b2CircleShape(p2m(radius));
			ball.SetRadius(p2m(radius));
			var ballFixDef:b2FixtureDef = _door.addFixtureDef(ball, density, friction, restitution);
			body.CreateFixture(ballFixDef);
			return body;
		}
		
		private function addCorners(cornerId:int, density:Number = 0, friction:Number = 0, restitution:Number = 0):void {
			var bodyDef:b2BodyDef = new b2BodyDef();
			bodyDef.type = b2Body.b2_staticBody;
			bodyDef.position.Set(0,0);
			var body:b2Body = this._world.CreateBody(bodyDef);
			var polygon:b2PolygonShape = new b2PolygonShape();
			var vecs:Array = setCorner(cornerId);
			polygon.SetAsArray(vecs,vecs.length);
			//polygon.set
			var fixDef:b2FixtureDef =_door.addFixtureDef(polygon, density, friction, restitution);
			body.CreateFixture(fixDef);
		}
		
		private function p2m(pix:Number):Number {
			return pix / PIXELS_TO_METRE;
		}
		//private function 
		
		private function setCorner(cid:int):Array {
			var arr0:Array = [[0, 0], [CL, 0], [CL, THICHNESS], [THICHNESS, CL], [0, CL]];
			var arr1:Array = [[W, 0], [W, CL], [W - THICHNESS, CL], [W - CL, THICHNESS], [W - CL, 0]];
			var arr2:Array = [[0, H], [0, H-CL], [THICHNESS, H-CL], [CL, H - THICHNESS], [CL, H]];
			var arr3:Array = [[W, H], [W - CL, H], [W - CL, H - THICHNESS], [W - THICHNESS, H - CL], [W, H - CL]];
			var coners:Array = [arr0,arr1,arr2,arr3];
			var vertices:Array = new Array();
			for (var i:int = 0; i < 5; i++) {
				vertices[i]=new b2Vec2(p2m(coners[cid][i][0]), p2m(coners[cid][i][1]));
			}
			return vertices;
		}
		

		
		private function debugDraw():Sprite {
			var debugDraw:b2DebugDraw = new b2DebugDraw();
			var debugSprite:Sprite = new Sprite();
			debugDraw.SetSprite(debugSprite);
			debugDraw.SetDrawScale(PIXELS_TO_METRE);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
			debugDraw.SetFillAlpha(0.5);
			this._world.SetDebugDraw(debugDraw);
			return debugSprite;
		}

		public function worldUpdate(evt: Event):void {
			var timeStep:Number = 1 / 30;
			var velocityIterations:int = 6;
			var positionIterations:int = 2;
			for (var i:int = 0; i <_gates.length; i++) {
				var gate:b2Body = _gates[i];
				gate.ApplyTorque(forceD[i]*25);
			}
			this._world.Step(timeStep, velocityIterations, positionIterations);
			this._world.ClearForces();
			this._world.DrawDebugData();
		}
		
		
		public function onKeyboardEvent(event:KeyboardEvent):void {
			switch (event.keyCode) {
				case Keyboard.UP :
				for (var i:int = 0; i <_gates.length; i++) {
					var gate:b2Body = _gates[i];
					gate.ApplyTorque(forceD[i]*-625);
				}
				
					break;
				case Keyboard.DOWN :
					//_aaa.ApplyTorque( -1600.0);
					break;
				case Keyboard.LEFT :
					
					break;
				case Keyboard.RIGHT :
					
				break;
					default :
				break;
			}

		}


   }
}